/**
 * @brief 这是一个观察者模式框架模块。
 * @version 1.1
 * @author 宋炜
 * @date 
 *     2024-3-19  1.1  增加线程池异步通知功能
 */
#pragma once
 
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
#include <tuple>

#include "container/variant.hpp"

#if OBSERVER_ENABLE_AYSNC == 1
#	ifndef OBSERVER_THD_COUNT
#		define OBSERVER_THD_COUNT (4)
#	endif
#	include "threadPool.hpp"
#endif

namespace wheels{namespace dm	{
/**
 * @brief 观察数据变化的模块接口
 */
class observer {
public:
    virtual ~observer(){}
    virtual void update( const std::vector< wheels::variant> & data ) = 0;
    // 内部使用
    virtual bool needRelease(){ return false; }
};

/**
 * @brief 抽取tuple数据内容构造参数表的vector
 */
template< int N , typename tupleType >
struct FOR__{
	/**
	 * 
	*/
    static void extract( std::vector< wheels::variant >& param , const tupleType& t ){
        param[ N ] = wheels::variant::make( std::get< N >( t ) );
        FOR__< N - 1 , tupleType >::extract( param , t );
    }
};

template< typename tupleType >
struct FOR__<0, tupleType >{
    static void extract( std::vector< wheels::variant >& param  , const tupleType& t ){
        param[ 0 ] = wheels::variant::make(std::get< 0 >( t ) );
    }
};

/**
 * @brief 数据改变的模块
 */
class subject {
public:
    using obsvFunc_t = std::function< void ( const std::vector<wheels::variant>& ) >;
protected:


    class observer__ : public observer{
    private:
        obsvFunc_t  m_func__;
    public:
        observer__( obsvFunc_t func ):m_func__( func ){}
        virtual ~observer__(){}

        virtual void update( const std::vector< wheels::variant > & data ) final{ m_func__( data ); }
        virtual bool needRelease() final{ return true; }
    };

public:
    subject(){
#if OBSERVER_ENABLE_AYSNC == 1
		int thd_count = 4;

#	if defined( OBSERVER_THD_COUNT )
		thd_count = OBSERVER_THD_COUNT;
#   endif
		pt_thd_pool__ = std::make_shared< threadPool >(thd_count);
		pt_thd_pool__->start();
#endif

	}
    virtual ~subject(){
#if OBSERVER_ENABLE_AYSNC == 1
		if( pt_thd_pool__ ){
			pt_thd_pool__->stop();
		}
#endif
	}
    /**
     * @brief 添加观察者对象
     */
    template< typename realType >
    void addObserver( realType* obsv ) {
        std::unique_lock< std::mutex > lck( m_mutex__ );
        m_observers__.push_back( obsv );
    }

    /**
     * @brief 添加观察者函数
     */
    observer* addObserver( obsvFunc_t func ) {
        observer * ret = nullptr;
        try{
            ret = new observer__(  func );
            {
                std::unique_lock< std::mutex > lck( m_mutex__ );
                m_observers__.push_back( ret );
            }
        }catch( std::bad_alloc& e ){
            std::cout << e.what() <<std::endl;
        }

        return ret;
    }
    /**
     * @brief 移除观察者对象
     */
    void removeObserver( observer* obsv ) {
        std::unique_lock< std::mutex > lck_( m_mutex__ );
        if( m_observers__.size() == 0 ) return;

        auto it = std::find(m_observers__.begin(), m_observers__.end(), obsv );
        if (it != m_observers__.end()) {
            if( (*it)->needRelease() ){
                delete ( *it );
            }
            m_observers__.erase(it);
        }
    }

    /**
     * @brief 执行通知操作
     */
    template< typename ...Args >
    void notifyObservers( Args&&... args) {
        // 构造variant数组
        if( sizeof...( args ) > 0 ){
            auto t = std::make_tuple( std::forward<Args>( args )... );
            std::vector< wheels::variant >   param( sizeof...( args ) );
            // 从tuple抽取参数构造成 std::vector< wheels::variant >
            FOR__< sizeof...(args) - 1 , decltype(t) >::extract( param, t );
            std::lock_guard< std::mutex > lck( m_mutex__ );
            for (auto obsv : m_observers__) {
                obsv->update( param );
            }
        }else{
            std::vector< wheels::variant > param;
            std::lock_guard< std::mutex > lck( m_mutex__ );
            for (auto obsv : m_observers__) {
                obsv->update( param );
            }
        }
    }
#if OBSERVER_ENABLE_AYSNC == 1
	template< typename ...Args >
    void notifyObserversAsync( Args&&... args) {
        // 构造variant数组
        if( sizeof...( args ) > 0 ){
            auto t = std::make_tuple( std::forward<Args>( args )... );
            std::vector< wheels::variant >   param( sizeof...( args ) );
            // 从tuple抽取参数构造成 std::vector< wheels::variant >
            FOR__< sizeof...(args) - 1 , decltype(t) >::extract( param, t );

            for (auto obsv : m_observers__) {
				pt_thd_pool__->enqueue( [=](){
					std::lock_guard< std::mutex > lck( m_mutex__ );
					obsv->update( param );
				});
            }
        }else{
            std::vector< wheels::variant > param;
            std::lock_guard< std::mutex > lck( m_mutex__ );
            for (auto obsv : m_observers__) {
                pt_thd_pool__->enqueue( [=](){
					std::lock_guard< std::mutex > lck( m_mutex__ );
					obsv->update( param );
				});
            }
        }
    }
#endif
private:
    std::mutex                 m_mutex__;
    std::vector< observer* >   m_observers__;
#if OBSERVER_ENABLE_AYSNC == 1
	std::shared_ptr< threadPool >   pt_thd_pool__;
#endif
};
}}

